
#pragma once
 
#include <iostream>
#include <cstdio>
#include <string>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "Comm.hpp"
#include <unistd.h>


const int gdefaultid = -1;
const int gsize = 4096;
const std::string pathname = ".";
const int projid = 0x66;
const int gmode = 0666;
#define CREATER "creater"
#define USER "user"

//  描述共享内存的类
class Shm
{
private:
    void Createhelp(int flg)
    {
        key_t key=ftok(pathname.c_str(),projid);
        if(key<0)
        {
            ERR_EXIT("ftok");
        }
        //创建共享内存
        _shmid=shmget(key,_size,flg);
        if(_shmid<0)
        {
            ERR_EXIT("shmget");
        }
    }

    //  创建共享内存资源
    void Create()
    {
        Createhelp(IPC_CREAT | IPC_EXCL | gmode);
    }

    //  关联共享内存资源
    void Attach()
    {
        _start_mem = shmat(_shmid, nullptr, 0);
        if ((long long)_start_mem < 0)
        {
            ERR_EXIT("shmat");
        }
        std::cout << "关联共享内存资源成功" << std::endl;
    }

    //  取消关联
    void Detach()
    {
        int n = shmdt(_start_mem);
        if (n == 0)
        {
            printf("取消关联成功\n");
        }
    }

    //  获取共享内存资源
    void Get()
    {
        Createhelp(IPC_CREAT);
    }

    //  释放共享内存资源
    void Destroy()
    {
        shmctl(_shmid, IPC_RMID, nullptr);
    }

public:

    // pathname 和 projid 用于构建 key 值，usertype用于标记使用者身份
    Shm(const std::string &pathname, const int projid, const std::string &usertype)
    : _shmid(gdefaultid)
    , _size(gsize)
    , _start_mem(nullptr)
    , _user_type(usertype)
    {
        if (_user_type == CREATER)
        {
            Create();
        }
        else if (_user_type == USER)
        {
            Get();
        }
        else
        {
 
        }
        Attach();
    }

    // 取消共享内存的关联对象，如果使用者身份为创建者，则释放共享内存资源
    ~Shm()
    {
        std::cout << _user_type << std::endl;
        if (_user_type == CREATER)
        {
            Destroy();
        }
    }

    // 获取起始虚拟地址
    void* VirtualAddr()
    {
        printf("virtual address: %p\n", _start_mem);
        return _start_mem;
    }
 
    //  获取共享内存大小
    int size()
    {
        return _size;
    }
 
    //  获取共享内存信息
    void Attr()
    {
        struct shmid_ds ds;
        int n = shmctl(_shmid, IPC_STAT, &ds);
        printf("shm_segsz: %ld\n", ds.shm_segsz);
        printf("key: 0x%x\n", ds.shm_perm.__key);
    }

private:
    int _shmid; //共享内存id号
    key_t _key; //共享内存的key值，标识唯一性
    int _size;  //共享内存的空间大小
    void *_start_mem;   //共享内存的起始虚拟地址
    std::string _user_type; //共享内存的使用者身份
};